-
Notifications
You must be signed in to change notification settings - Fork 171
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
refactor(iroh): Allow to register custom protocols #2358
Conversation
a439a5f
to
9a46f6f
Compare
9a46f6f
to
a369048
Compare
40f734f
to
5703d6e
Compare
iroh/src/node/builder.rs
Outdated
/// Note that the client returned from [`Self::client`] can only be used after spawning the node, | ||
/// until then all RPC calls will time out. | ||
#[derive(derive_more::Debug)] | ||
pub struct UnspawnedNode<D, E> { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Maybe call this CustomProtocolBuilder since you will use it only when you want to register custom protocols? Naming 🤷
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Went with ProtocolBuilder
for now. Open to changing further :)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Added a bunch of comments. Overall looks great.
Addressed most review comments. And:
Other public API namings we could bikeshed a bit:
I think I'm fine with the current namings, but also very open to changing if others find other names more intuitive. |
I don't hate trait Protocol, but like ProtocolHandler a bit more. For me a protocol is a rust module containing a bunch of request and response types, usually in some enums, and some help text describing how to use them (e.g. serialize them with postcard), not something active. Or maybe AcceptHandler? After all the "active/outgoing" part of the protocol might live somewhere else.
I think accept is fine. I mean, this is basically building a dispatcher for accept. As mentioned above, this part is only for the listen/accept part of the protocol, the active part will usually be created before using the iroh-net endpoint and then maybe end up in some tokio task. |
Not sure if we want to address this in this PR or the next, but in Builder::build it now always calls register_iroh_protocols. So there is no way to opt out of them, just to add extra protocols. I wasn't quite sure how it should look if you want to have a "naked" node. Also, it seems that we are not really ready to create a naked node. So maybe let's do it in the next PR that will allow disabling docs. |
I renamed
Yup, let's defer this to a followup. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I like this approach of structured concurrency, essentially the same as I did in iroh-relay. Also TIL about SharedAbortingJoinHandle. I'm a little unsure if there's any downsides to having many clones of the JoinHandle, but let's see. It makes it a lot easier to use.
}) | ||
} | ||
|
||
/// Set the list of accepted ALPN protocols. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
/// Set the list of accepted ALPN protocols. | |
/// Sets the list of accepted ALPN protocols. |
unspawned_node.spawn().await | ||
} | ||
|
||
/// Build a node without spawning it. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
/// Build a node without spawning it. | |
/// Builds a node without spawning it. |
iroh/src/node/builder.rs
Outdated
|
||
/// Build a node without spawning it. | ||
/// | ||
/// Returns an `UnspawnedNode`, on which custom protocols can be registered with |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
/// Returns an `UnspawnedNode`, on which custom protocols can be registered with | |
/// Returns an [`UnspawnedNode`], on which custom protocols can be registered with |
} | ||
|
||
impl<D: iroh_blobs::store::Store, E: ServiceEndpoint<RpcService>> ProtocolBuilder<D, E> { | ||
/// Register a protocol handler for incoming connections. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
/// Register a protocol handler for incoming connections. | |
/// Registers a protocol handler for incoming connections. |
self | ||
} | ||
|
||
/// Return a client to control this node over an in-memory channel. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
/// Return a client to control this node over an in-memory channel. | |
/// Returns a client to control this node over an in-memory channel. |
self.protocols.get_typed(alpn) | ||
} | ||
|
||
/// Register the core iroh protocols (blobs, gossip, docs). |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
/// Register the core iroh protocols (blobs, gossip, docs). | |
/// Registers the core iroh protocols (blobs, gossip, docs). |
self | ||
} | ||
|
||
/// Spawn the node and start accepting connections. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
/// Spawn the node and start accepting connections. | |
/// Spawns the node and start accepting connections. |
|
||
impl ProtocolMap { | ||
/// Returns the registered protocol handler for an ALPN as a concrete type. | ||
pub fn get_typed<P: ProtocolHandler>(&self, alpn: &[u8]) -> Option<Arc<P>> { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Could we have the same visibility marker here as on the struct, so pub(super)
? I find that a lot easier to read. Plus there's fewer surprises: if the super module decides to export this than suddenly these functions are really pub, and that might have been unintended.
self.0.get(alpn).cloned() | ||
} | ||
|
||
/// Insert a protocol handler. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
/// Insert a protocol handler. | |
/// Inserts a protocol handler. |
self.0.keys() | ||
} | ||
|
||
/// Shutdown all protocol handlers. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
/// Shutdown all protocol handlers. | |
/// Shuts down all protocol handlers. |
## Description Addresses review by @flub on #2358 (which is already merged). ## Breaking Changes <!-- Optional, if there are any breaking changes document them, including how to migrate older code. --> ## Notes & open questions <!-- Any notes, remarks or open questions you have to make about the PR. --> ## Change checklist - [x] Self-review. - [x] Documentation updates if relevant. - [ ] ~~Tests if relevant.~~ - [x] All breaking changes documented.
* feat(iroh-net): Allow to set the list of accepted ALPN protocols at runtime * refactor(iroh): Spawning a node can now be performed in two stages: First `Builder::build()` is called, which returns a Future that resolves to a new type `ProtocolBuilder`. The `ProtocolBuilder` is then spawned into the actual, running `Node`. If the intermediate step is not needed, `Builder::spawn` performs both in one call, therefore this change is not breaking. * feat(iroh): Allow to accept custom ALPN protocols in an Iroh node. Introduce a `ProtocolHandler` trait for accepting incoming connections and adds `ProtocolBuilder::accept` to register these handlers per ALPN. * refactor(iroh): Move towards more structured concurrency by spawning tasks into a `JoinSet` * refactor(iroh): Improve shutdown flow and perform more things concurently. originally based on n0-computer#2357 but now directly to main * `iroh_net::endpoint::make_server_config` takes `Arc<quinn::TransportConfig>` instead of `Option<quinn::TransportConfig>`. If you used the `None` case, replace with `quinn::TransportConfig::default()`. <!-- Any notes, remarks or open questions you have to make about the PR. --> - [x] Self-review. - [x] Documentation updates if relevant. - [ ] Tests if relevant. - [x] All breaking changes documented.
## Description Addresses review by @flub on n0-computer#2358 (which is already merged). ## Breaking Changes <!-- Optional, if there are any breaking changes document them, including how to migrate older code. --> ## Notes & open questions <!-- Any notes, remarks or open questions you have to make about the PR. --> ## Change checklist - [x] Self-review. - [x] Documentation updates if relevant. - [ ] ~~Tests if relevant.~~ - [x] All breaking changes documented.
Description
Builder::build()
is called, which returns a Future that resolves to a new typeProtocolBuilder
. TheProtocolBuilder
is then spawned into the actual, runningNode
. If the intermediate step is not needed,Builder::spawn
performs both in one call, therefore this change is not breaking.ProtocolHandler
trait for accepting incoming connections and addsProtocolBuilder::accept
to register these handlers per ALPN.JoinSet
originally based on #2357 but now directly to main
Breaking Changes
iroh_net::endpoint::make_server_config
takesArc<quinn::TransportConfig>
instead ofOption<quinn::TransportConfig>
. If you used theNone
case, replace withquinn::TransportConfig::default()
.Notes & open questions
Change checklist